package com.lagou.edu.factory;

import com.lagou.edu.annotation.Autowired;
import com.lagou.edu.annotation.Service;
import com.lagou.edu.annotation.Transaction;
import org.reflections.Reflections;
import org.reflections.scanners.FieldAnnotationsScanner;
import org.reflections.scanners.MethodAnnotationsScanner;
import org.reflections.scanners.MethodParameterScanner;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.util.ConfigurationBuilder;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.lang.model.type.DeclaredType;

public class AnnoBeanFactory {

    private static Map<String, Object> map = new HashMap<>(); // 存储对象

    // 1. 扫描包下的class，把有@Service注解的类实例化放到Map中
    static {
        Reflections reflections = new Reflections(new ConfigurationBuilder().forPackages("com.lagou.edu") // 指定路径URL
                .addScanners(new SubTypesScanner()) // 添加子类扫描工具
                .addScanners(new FieldAnnotationsScanner()) // 添加 属性注解扫描工具
                .addScanners(new MethodAnnotationsScanner()) // 添加 方法注解扫描工具
                .addScanners(new MethodParameterScanner()) // 添加方法参数扫描工具
        );

        // 通过反射技术获取有Services注解的类，把他们的实例放到map里
        Set<Class<?>> services = reflections.getTypesAnnotatedWith(Service.class);
        System.out.println("Service count: " + String.valueOf(services.size()));
        for (Class<?> clas : services) {
            Service aService = clas.getAnnotation(Service.class);
            // System.out.println("The service>>>>" + clas + " annotated with: " + aService.id());
            try {
                Object o = clas.newInstance();
                map.put(aService.id(), o);
            } catch (InstantiationException | IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        // 获取有@autowired注解的所有属性并进行自动装配
        Set<Field> aFields = reflections.getFieldsAnnotatedWith(Autowired.class);
        System.out.println("Fields count: " + aFields.size());
        for (Field aField : aFields) {
            // 从map里拿出设定的依赖并进行依赖注入
            Autowired autowired = aField.getAnnotation(Autowired.class);
            System.out.println(">>>Field autowire annotation value: " + autowired.depid());
            String depClasId = autowired.depid();
            // 获取申明的类型
            Type declaredType = aField.getGenericType();
            // System.out.println("declaredType: " + declaredType.toString() + " depClasId: " + depClasId + " " +  "ownerClass" + ": " + autowired.owner());
            try {
                Object pObj = map.get(autowired.owner());
                aField.setAccessible(true);
                Object dObj = map.get(depClasId);
//                if (dObj instanceof declaredType) {
                    aField.set(pObj, dObj);
//                } else {
//                    throw new Exception("类型不匹配");
//                }
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        // 为@Transaction类添加代理, 并使用代理类代替原有类
        Set<Class<?>> trans = reflections.getTypesAnnotatedWith(Transaction.class);
        for (Class<?> clas : trans) {
            Transaction transactionAnnotation = clas.getAnnotation(Transaction.class);
            ProxyFactory proxyFactory = (ProxyFactory) map.get(transactionAnnotation.proxy());
            Service aService = clas.getAnnotation(Service.class);
            String aServiceId = aService.id();
            map.put(aServiceId, proxyFactory.getJdkProxy(map.get(aServiceId)));
        }
    }

    // 对外提供获取实例对象的接口（根据id获取）
    public static Object getBean(String id) {
        return map.get(id);
    }
}
